<?php


namespace app\index\controller;


use design\Factory;
use design\Page;

class Design
{
    public function __construct()
    {
        // 动态设置
        app()->config->set('app_trace', false);
    }
    
    public function index()
    {
        # 测试栈 先进后出
        $stack = new \SplStack();
        $stack->push(1);
        $stack->push(2);
        echo $stack->pop(), PHP_EOL; // 2
        echo $stack->pop(), PHP_EOL; // 1

        # 测试队列 先进先出
        $queue = new \SplQueue();
        $queue->enqueue(1);
        $queue->enqueue(2);
        echo $queue->dequeue(), PHP_EOL;  // 1
        echo $queue->dequeue(), PHP_EOL;  // 2

        # 最小堆
        $minHeep = new \SplMinHeap();
        $minHeep->insert(1);
        $minHeep->insert(2);
        echo $minHeep->extract(), PHP_EOL;
        echo $minHeep->extract(), PHP_EOL;

        # 固定长度的数组
        $fixedArray = new \SplFixedArray(5);
        $fixedArray[1] = 1;
        $fixedArray[3] = 6;
        var_dump($fixedArray);


        # 链式操作 方法本身返回$this
        $db = new \design\Database();
        $res = $db->table()->where()->order()->limit()->delete();
        var_dump($res);

        # 类的魔术方法
        $obj = new \design\SuperMethod();
        $obj->title = '标题';
        $res = [
            $obj->title,
            $obj->say('hello', 'world'),
            \design\SuperMethod::say("static", 'hello'),
            $obj . '',
            $obj('name', 'age', 'others'),
        ];
        var_dump($res);

        # 工厂模式  通过工厂类来创建不同的db类
        $db = \design\Factory::createDatabase('mysql');
        $db->where()->delete();

        # 单例模式  通过静态类来控制只返回单一实例
        $db = \design\SingleDatabase::getInstance();
        $db->where()->find();


        # 工厂加单例 (多种数据库) 通过工厂类创建返回单例类单一实例
        $db = \design\Factory::singleDatabase('mysql');
        $db->where()->find();

        # 注册器模式 通过静态类属性保存和获取对象
        $db = \design\Factory::singleRegisterDatabase('mysql');
        $db = \design\Register::get('database'); // 从注册器获取db

        # 适配器模式  通过实现共同接口而具有相同方法 (使不同环境有相同使用方式)
        // $db = new \design\database\Mysql();
        // 如果使用的是mysqli,
        $db = new \design\database\Mysqli();
        // 如果使用的是sql_server,
        // $db = new \design\database\SqlServer();
        $db->connect('localhost', 'llqhz', 'llqhz', 'llqhz');
        $list = $db->query('select * from user where id = 2');
        $db->close();
        var_dump($list);

        # 策略模式 根据不同策略来实现不同的行为 (需要构造策略接口及其实现类)
        $page = new Page();
        $strategy = new \design\strategy\MaleStrategy();
        // 如果新增一种策略,只需新建策略实现类,然后在这里设置即可
        $page->setStrategy($strategy);
        $page->index();

        // 策略模式的依赖注入和控制反转
        // link:https://blog.csdn.net/u014563989/article/details/55188673
        // link:https://www.jianshu.com/p/002542f9c854
        // page类依赖strategy类，page对strategy类型有自主控制券
        // 当设计setStrategy时，page对strategy类型失去控制权，此时是控制反转，由外部控制strategy类型
        // 但是page类依赖strategy类，需要指定strategy类page才能正常运行：
        // 有3种方式: 1构造函数传入, 2(属性注入)setter指定,
        // 扩展:(接口):通过page_interface 指定所有page依赖setter, 确保page类必须提供setter
        $page = new \design\PageDefault();
        $page->index();


        # 数据对象映射模式 ORM
        $user = new \design\UserModel(1);
        $user->name = date("Y-m-d H:i:s");
        var_dump($user->name);

        # 对象映射+工厂+注册器
        $user1 = \design\Factory::getUser(2);
        $user2 = \design\Factory::getUser(2);
        $user1->name = 'name1';
        $user2->name = 'name2';
        var_dump([$user1, $user2]);

        # 观察者模式 基于事件的触发更新机制
        $event = new \design\observer\ClickEvent();
        $event->trigger();
        $event->addObserver(new \design\observer\Observer1());
        $event->trigger();
        $event->addObserver(new \design\observer\Observer2());
        $event->trigger();
        // tips: 事件通知和观察者管理抽离在基类完成， 观察者体系由observerInterface维护
        // 此模式涉及依赖注入，由外部通过setter注入属性依赖, 也有控制反转:observer从由内部写死到由外部指定


        # 原型模式 通过clone原型对象来创建对象,而不是每次都自己 (创建大对象时可节省内存)
        $prototype = new \design\Canvas();
        $prototype->init();

        $canvas1 = clone $prototype;
        $canvas1->rect(2, 3, 4,5);
        $canvas1->draw();
        echo PHP_EOL;
        $canvas2 = clone $prototype;
        $canvas2->rect(1, 2, 5,5);
        $canvas2->draw();
        # clone 的是初始化之后的状态，之后的更改都是复制而不是指针引用


        # 装饰器模式 动态地添加和修改类的功能(decorator)
        $canvas = new \design\decorator\CanvasWithDecorator();
        $canvas->init();
        $canvas->addDecorator(new \design\decorator\LineDecorator('+'));
        $canvas->addDecorator(new \design\decorator\ColorDecorator('green'));
        $canvas->rect(1, 1, 7, 7);
        $canvas->draw();


    }
    
    
}